/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { OriginalClassGenerator } from './generators/OriginalClassGenerator';
import { SendableClassGenerator } from './generators/SendableClassGenerator';
import { SerializerGenerator } from './generators/SerializerGenerator';
import { ImportManager } from './shared/ImportManager';
import { ClassAnalysis, IGeneratedFile, Logger, ITaskContext, GenerationContext } from '../..';
import SerializationPathUtil from '../../utils/SerializationPathUtil';
import { CustomError, ErrorCodes } from '../../utils/CustomError';
import { TsMorphUtil } from '../../utils/TsMorphUtil';

export class CodeGenerationService {
  private readonly importManger: ImportManager;
  private readonly originalClassGenerator: OriginalClassGenerator;
  private readonly serializerGenerator: SerializerGenerator;
  private readonly sendableGenerator: SendableClassGenerator;

  constructor() {
    this.importManger = new ImportManager();

    this.originalClassGenerator = new OriginalClassGenerator(this.importManger);
    this.serializerGenerator = new SerializerGenerator(this.importManger);
    this.sendableGenerator = new SendableClassGenerator();
  }

  generateForSourceFile(sourcePath: string, results: ClassAnalysis[], context: ITaskContext): IGeneratedFile | null {
    Logger.debug(`开始为 ${sourcePath} 文件生成代码: ${results.length} 个类`);
    this.importManger.setContext(context);
    // 1. 生成Sendable文件（sendableModel目录）- 包含Sendable类
    this.generateSendableModelFiles(results, context);
    // 2. 生成主文件（model目录）- 包含原始类、序列化器、toSendable方法
    return this.generateMainModelFile(sourcePath, results, context);
  }

  private generateMainModelFile(
    sourceFileAbs: string,
    results: ClassAnalysis[],
    context: ITaskContext
  ): IGeneratedFile | null {
    const originalSourceFile = TsMorphUtil.getProject().addSourceFileAtPath(sourceFileAbs);
    // 计算输出路径
    const outputPath = context.mapToOutputPath(sourceFileAbs);
    // 确保输出目录存在
    context.ensureOutputDirectory(outputPath);
    // 验证输出路径有效性
    if (!context.isValidOutputPath(outputPath)) {
      throw new CustomError(`输出路径无效: ${outputPath}`, ErrorCodes.INVALID_OUTPUT_FAIL);
    }
    // 创建输出文件
    const outputSourceFile = TsMorphUtil.getProject().createSourceFile(outputPath, '', { overwrite: true });

    const serializableGeneratorContext: (GenerationContext | string)[] = [];
    for (const classAnalysis of results) {
      serializableGeneratorContext.push(this.serializerGenerator.generate(outputSourceFile, classAnalysis, context));
    }

    // 生成原始类结构
    this.originalClassGenerator.generate(outputSourceFile, originalSourceFile, results);

    for (const content of serializableGeneratorContext) {
      this.serializerGenerator.generateRegistration(outputSourceFile, content);
    }

    // 添加导入语句
    this.importManger.getImportDeclarations().forEach((importDeclaration) => {
      outputSourceFile.addImportDeclaration({
        moduleSpecifier: importDeclaration.specifier,
        namedImports: [...new Set(importDeclaration.names)]
      });
    });
    this.importManger.getDefaultImport().forEach((importDeclaration) => {
      outputSourceFile.addImportDeclaration({
        moduleSpecifier: importDeclaration.specifier,
        defaultImport: importDeclaration.name
      });
    });
    // 格式化代码
    outputSourceFile.formatText();
    // 保存文件
    outputSourceFile.saveSync();
    // 返回生成结果
    this.cleanup();
    return {
      sourcePath: sourceFileAbs,
      outputPath,
      contentLength: outputSourceFile.getFullText().length,
      serializerCount: results.length,
      generatedAt: Date.now()
    };
  }

  private generateSendableModelFiles(results: ClassAnalysis[], context: ITaskContext): void {
    for (const classAnalysis of results) {
      // 跳过可合并的类（它们已经在主文件中生成为Sendable类）
      if (classAnalysis.canMerge) {
        Logger.debug(`类 ${classAnalysis.className} 采用合并策略，跳过独立Sendable文件生成`);
        continue;
      }

      // 双版本策略：生成独立的Sendable文件
      if (this.sendableGenerator.canHandle(classAnalysis)) {
        this.generateSendableFile(classAnalysis, context);
      }
    }
  }

  private generateSendableFile(result: ClassAnalysis, context: ITaskContext): void {
    Logger.debug(`类 ${result.className} 采用独立Sendable文件生成`);
    const sendableOutputPath = SerializationPathUtil.mapToSendableOutputPath(result.className, context);
    context.ensureOutputDirectory(sendableOutputPath);
    const sendableImportManager = new ImportManager();
    sendableImportManager.setContext(context);
    sendableImportManager.registerArkTSImports(['lang']);
    const sendableSourceFile = TsMorphUtil.getProject().createSourceFile(sendableOutputPath, '', { overwrite: true });
    this.sendableGenerator.generate(sendableSourceFile, result, sendableImportManager);
    if (this.sendableGenerator.needsCollectionsImport(result)) {
      this.importManger.registerArkTSImports(['collections']);
    }
    this.importManger.registerCustomTypeImport(sendableOutputPath, `Sendable${result.className}`);
    sendableImportManager.getImportDeclarations().forEach((importDeclaration) => {
      sendableSourceFile.addImportDeclaration({
        moduleSpecifier: importDeclaration.specifier,
        namedImports: [...new Set(importDeclaration.names)]
      });
    });
    sendableImportManager.getDefaultImport().forEach((importDeclaration) => {
      sendableSourceFile.addImportDeclaration({
        moduleSpecifier: importDeclaration.specifier,
        defaultImport: importDeclaration.name
      });
    });
    sendableSourceFile.formatText();
    sendableSourceFile.saveSync();
  }

  // ============= 验证和清理 =============

  private cleanup(): void {
    // 注意import是共享的，所以每个文件生成结束以后需要清空
    this.importManger.clear();

    // 清理项目缓存
    // 注意：不要完全dispose project，因为它可能被重复使用
  }
}
